<?php
/*
 * @Description    : 微信公众平台入口
 * @Author         : QianLong
 * @Date           : 2022-07-18 10:55:08
 * @LastEditors    : QianLong
 * @LastEditTime   : 2024-05-10 09:48:52
 */

declare(strict_types=1);

namespace App\Controller;

use App\Exception\ApiException;
use App\Service\Weixin\WXBizMsgCrypt;
use Yurun\Util\HttpRequest;

class MpWeixinController extends AbstractController
{
  public function callback($mw_id = '')
  {
    $param = $this->request->all();
    $file = BASE_PATH . '/runtime/dev.txt';
    // file_put_contents($file, '进入回调' . "\r\n", FILE_APPEND);
    // file_put_contents($file, json_encode($param) . "\r\n", FILE_APPEND);
    if (empty($mw_id)) {
      throw new ApiException(-1, '公众号ID不能为空');
    }
    $infoData = $this->redisCache->getMpWxInfo($mw_id);
    $method = $this->request->getMethod();
    $this->mpWeixin->checkSignature($param, $infoData['token']);
    if (strtoupper($method) == 'GET') {
      return $this->response->raw($param['echostr']);
    }
    $returnWx = $param;
    if ($infoData['aes_type'] == 'secure' || $infoData['aes_type'] == 'jianrong') {
      $wxCrypt = new WXBizMsgCrypt($infoData['token'], $infoData['aes'], $infoData['app_id']);
      $errCode = $wxCrypt->decryptMsg($param['msg_signature'], $param['timestamp'], $param['nonce'], $param['Encrypt'], $data);
      if ($errCode == 0) {
        $returnWx = $data;
      }
    }
    $userInfo = $this->redisCache->getUserInfoById($infoData['uid']);
    if ($userInfo['status'] != 1) {
      unset($userInfo);
      return $this->wxNoticeText('用户状态不正常，请联系柠聚开发平台客服进行处理。柠聚开发官网：http://www.21ds.cn', $returnWx['ToUserName'], $returnWx['FromUserName']);
    }
    if ($infoData['status'] != 1) {
      return $this->wxNoticeText('当前配置状态不可用，如需使用，请登录柠聚开发平台启用后重试。柠聚开发官网：http://www.21ds.cn', $returnWx['ToUserName'], $returnWx['FromUserName']);
    }
    switch (strtolower($returnWx['MsgType'])) {
      case 'text':
        return $this->getTextMsg($returnWx['Content'], $mw_id, $returnWx['ToUserName'], $returnWx['FromUserName']);
        break;
      case 'event':
        file_put_contents($file, json_encode($returnWx) . "\r\n", FILE_APPEND);
        $returnWx['EventKey'] = (!isset($returnWx['EventKey']) || empty($returnWx['EventKey']))?'':$returnWx['EventKey'];
        $returnWx['Event'] = (!isset($returnWx['Event']) || empty($returnWx['Event']))?'':$returnWx['Event'];
        return $this->getEventMsg($infoData['event_url'], $returnWx['Event'], $mw_id, $returnWx['ToUserName'], $returnWx['FromUserName'], $returnWx['EventKey']);
        break;
      case 'miniprogrampage':
        file_put_contents($file, json_encode($returnWx) . "\r\n", FILE_APPEND);
        return $this->wxNoticeText('收到一个小程序，信息解析如下：' . "\r\n\r\n\r\n标题：" . $returnWx['Title']. "\r\n\r\nAppId：" . $returnWx['AppId']. "\r\n\r\n页面路径：" . $returnWx['PagePath']. "\r\n\r\n缩略图：" . $returnWx['ThumbUrl'], $returnWx['ToUserName'], $returnWx['FromUserName']);
        break;
      default:
        return $this->wxNoticeText('未知的消息类型：'. $returnWx['MsgType'],$returnWx['ToUserName'], $returnWx['FromUserName']);
        break;
    }
    return $this->response->json(200);
  }
  public function getTextMsg($text, $mw_id, $fromUser, $toUser)
  {
    $http = new HttpRequest;
    $where['mw_id'] = $mw_id;
    $where['keyword_arr'] = ['$elemMatch' => ['$eq' => trim($text)]];
    $result = mongodb2()->mp_weixin_keyword->findOne($where);
    if (empty($result)) {
      $hasNeed = $this->redisCache->getNeedSecUser($toUser);
      if (!empty($hasNeed)) {
        $where['mw_id'] = $mw_id;
        $where['keyword_arr'] = ['$elemMatch' => ['$eq' => trim($hasNeed)]];
        $result = mongodb2()->mp_weixin_keyword->findOne($where);
      }
    }
    $result = json_decode(json_encode($result), true);
    if (!empty($result)) {
      if ($result['content_type'] == 'text') {
        switch ($result['type']) {
          case 'pic':
            return $this->wxNoticeImage($result['content'], $fromUser, $toUser);
            break;
          case 'yinpin':
            return $this->wxNoticeVoice($result['content'], $fromUser, $toUser);
            break;
          case 'video':
            return $this->wxNoticeVideo($result['content'], $fromUser, $toUser, $result['reply_title']);
            break;
          case 'tuwen':
            return $this->wxNoticeNews($result['reply_pic'], $fromUser, $toUser, $result['reply_title'], $result['reply_desc'], $result['reply_url']);
            break;
          default:
            return $this->wxNoticeText($result['content'], $fromUser, $toUser);
            break;
        }
      } else {
        if (isset($result['need_sec_reply']) && $result['need_sec_reply'] == '1') {
          $hasNeed = $this->redisCache->getNeedSecUser($toUser);
          if (empty($hasNeed)) {
            $this->redisCache->getNeedSecUser($toUser, $text);
            return $this->wxNoticeText($result['need_sec_msg'] . "\r\n".'(注：2分钟内回复有效)', $fromUser, $toUser);
          }
        }
        $response = $http->post($result['content'], ['content' => trim($text),'open_id'=>$toUser]);
        $responseArr = json_decode($response->body(), true);
        if (!empty($responseArr) && isset($responseArr['code']) && $responseArr['code'] == 200) {
          switch ($result['type']) {
            case 'pic':
              return $this->wxNoticeImage($responseArr['data']['media_id'], $fromUser, $toUser);
              break;
            case 'yinpin':
              return $this->wxNoticeVoice($responseArr['data']['media_id'], $fromUser, $toUser);
              break;
            case 'video':
              return $this->wxNoticeVideo($responseArr['data']['media_id'], $fromUser, $toUser, $responseArr['data']['reply_title']);
              break;
            case 'tuwen':
              return $this->wxNoticeNews($responseArr['data']['reply_pic'], $fromUser, $toUser, $responseArr['data']['reply_title'], $responseArr['data']['reply_desc'], $responseArr['data']['reply_url']);
              break;
            default:
              return $this->wxNoticeText($responseArr['data']['content'], $fromUser, $toUser);
              break;
          }
        }
        return $this->wxNoticeText('通过接口未获取到正确内容', $fromUser, $toUser);
      }
    } else {
      // 关键字匹配不到时走淘客转链
      $itemInfo = [];
      $whereDg['mw_id'] = $mw_id;
      $whereDg['is_use'] = 1;
      $dgResult = mongodb2()->mp_weixin_dg->findOne($whereDg);
      unset($whereDg);
      $dgResult = json_decode(json_encode($dgResult), true);
      if (!empty($dgResult) && isset($dgResult['content_type']) && !empty($dgResult['content_type'])) {
        if ($dgResult['content_type'] == 'ecapi' && isset($dgResult['ecapi_apkey']) && !empty($dgResult['ecapi_apkey'])) {
          if (strstr($text, 'jd.com')) {
            $platformType = 'jd';
            $item_info_url = 'http://api.web.ecapi.cn/jingdong/getJdUnionItems?apkey=' . $dgResult['ecapi_apkey'] . '&keyword=' . urlencode($text);
            $itemInfoResponse = $http->get($item_info_url);
            $itemInfoResult = json_decode($itemInfoResponse->body(), true);
            if ($itemInfoResult['code'] == 200) {
              $itemInfo['pict_url'] = $itemInfoResult['data']['list'][0]['imageInfo']['imageList'][0]['url'];
              $itemInfo['title'] = $itemInfoResult['data']['list'][0]['skuName'];
            }
            $apiUrl = 'http://api.web.ecapi.cn/jingdong/doItemCpsUrl?apkey=' . $dgResult['ecapi_apkey'] . '&autoSearch=1&key_id=' . $dgResult['ecapi_jd_key_id'] . '&autoSearch=1&materialId=' . urlencode($text);
          } else {
            $platformType = 'tb';
            $apiUrl = 'http://api.web.ecapi.cn/taoke/doItemHighCommissionPromotionLinkByAll?apkey=' . $dgResult['ecapi_apkey'] . '&tbname=' . urlencode($dgResult['ecapi_tbname']) . '&pid=' . $dgResult['ecapi_tbpid'] . '&hasiteminfo=1&tpwd=1&shorturl=1&content=' . urlencode($text);
          }
          $htmlResponse = $http->get($apiUrl);
          $htmlResult = json_decode($htmlResponse->body(), true);
          if ($htmlResult['code'] == 200) {
            if ($platformType == 'jd') {
              $htmlResult['data']['tpwd_str'] = $htmlResult['data']['shortURL'];
            }
            if (!empty($itemInfo)) {
              $htmlResult['data']['item_info'] = $itemInfo;
            }
            switch ($dgResult['type']) {
              case 'tuwen':
                return $this->wxNoticeNews($htmlResult['data']['item_info']['pict_url'], $fromUser, $toUser, $htmlResult['data']['item_info']['title'], $htmlResult['data']['item_info']['title'], $htmlResult['data']['item_url']);
                break;
              default:
                return $this->wxNoticeText($htmlResult['data']['item_info']['title'] . "\r\n" . $htmlResult['data']['tpwd_str'], $fromUser, $toUser);
                break;
            }
          }
        } else {
          $http = new HttpRequest;
          $response = $http->post($result['content'], ['content' => trim($text),'open_id'=>$toUser]);
          $responseArr = json_decode($response->body(), true);
          if (!empty($responseArr) && isset($responseArr['code']) && $responseArr['code'] == 200) {
            switch ($dgResult['type']) {
              case 'pic':
                return $this->wxNoticeImage($responseArr['data']['reply_pic'], $fromUser, $toUser);
                break;
              case 'tuwen':
                return $this->wxNoticeNews($responseArr['data']['reply_pic'], $fromUser, $toUser, $responseArr['data']['reply_title'], $responseArr['data']['reply_desc'], $responseArr['data']['reply_url']);
                break;
              default:
                return $this->wxNoticeText($responseArr['data']['content'], $fromUser, $toUser);
                break;
            }
          }
        }
      }
    }
    return $this->wxNoticeText('未查询到相关内容', $fromUser, $toUser);
  }
  public function getEventMsg($event_url, $event, $mw_id, $fromUser, $toUser, $eventKey = '')
  {
    $eventKey = str_replace('qrscene_', '', $eventKey);
    $http = new HttpRequest;
    if (!empty($eventKey)) {
      if (!empty($event_url)) {
        $event_url_array = explode("\n", $event_url);
        $eventKeyArr = explode('::', $eventKey);
        $eventApi = '';
        $defaultApi = '';
        if (count($event_url_array) > 1) {
          foreach ($event_url_array as $url) {
            $urlArr = explode('::',$url);
            if ($urlArr[0] == 'default' && empty($defaultApi)) {
              $defaultApi = $urlArr[1];
            }
            if (empty($eventApi) && $urlArr[0] == $eventKeyArr[0]) {
              $eventApi = $urlArr[1];
              break;
            }
          }
          if (empty($eventApi)) {
            $eventApi = $defaultApi;
          }
        } else {
          $urlArr = explode('::', $event_url_array[0]);
          $eventApi = isset($urlArr[1])? $urlArr[1]: $urlArr[0];
        }
        if (!empty($eventApi)) {
          $response = $http->post($eventApi, ['event_key' => $eventKey, 'event' => $event, 'open_id' => $toUser]);
          $responseArr = json_decode($response->body(), true);
          if (!empty($responseArr) && isset($responseArr['code']) && $responseArr['code'] == 200) {
            switch ($responseArr['data']['type']) {
              case 'pic':
                return $this->wxNoticeImage($responseArr['data']['media_id'], $fromUser, $toUser);
                break;
              case 'yinpin':
                return $this->wxNoticeVoice($responseArr['data']['media_id'], $fromUser, $toUser);
                break;
              case 'video':
                return $this->wxNoticeVideo($responseArr['data']['media_id'], $fromUser, $toUser, $responseArr['data']['reply_title']);
                break;
              case 'tuwen':
                return $this->wxNoticeNews($responseArr['data']['reply_pic'], $fromUser, $toUser, $responseArr['data']['reply_title'], $responseArr['data']['reply_desc'], $responseArr['data']['reply_url']);
                break;
              default:
              if (isset($responseArr['data']['content']) && !empty($responseArr['data']['content'])) {
                  return $this->wxNoticeText($responseArr['data']['content'], $fromUser, $toUser);
              }
                break;
            }
          }
        }
        return $this->response->raw('success');
      }
    }
    if ($event == 'subscribe') {
      $where['mw_id'] = $mw_id;
      $where['is_use'] = 1;
      $result = mongodb2()->mp_weixin_sub->findOne($where);
      $result = json_decode(json_encode($result), true);
      if (!empty($result)) {
        if ($result['content_type'] == 'text') {
          switch ($result['type']) {
            case 'pic':
              return $this->wxNoticeImage($result['content'], $fromUser, $toUser);
              break;
            case 'yinpin':
              return $this->wxNoticeVoice($result['content'], $fromUser, $toUser);
              break;
            case 'video':
              return $this->wxNoticeVideo($result['content'], $fromUser, $toUser, $result['reply_title']);
              break;
            case 'tuwen':
              return $this->wxNoticeNews($result['reply_pic'], $fromUser, $toUser, $result['reply_title'], $result['reply_desc'], $result['reply_url']);
              break;
            default:
              return $this->wxNoticeText($result['content'], $fromUser, $toUser);
              break;
          }
        } else {
          $response = $http->post($result['content'], ['content' => 'subscribe', 'open_id' => $toUser]);
          $responseArr = json_decode($response->body(), true);
          if (!empty($responseArr) && isset($responseArr['code']) && $responseArr['code'] == 200) {
            switch ($result['type']) {
              case 'pic':
                return $this->wxNoticeImage($responseArr['data']['media_id'], $fromUser, $toUser);
                break;
              case 'yinpin':
                return $this->wxNoticeVoice($responseArr['data']['media_id'], $fromUser, $toUser);
                break;
              case 'video':
                return $this->wxNoticeVideo($responseArr['data']['media_id'], $fromUser, $toUser, $responseArr['data']['reply_title']);
                break;
              case 'tuwen':
                return $this->wxNoticeNews($responseArr['data']['reply_pic'], $fromUser, $toUser, $responseArr['data']['reply_title'], $responseArr['data']['reply_desc'], $responseArr['data']['reply_url']);
                break;
              default:
                return $this->wxNoticeText($responseArr['data']['content'], $fromUser, $toUser);
                break;
            }
          }
          return $this->wxNoticeText('通过接口未获取到正确内容', $fromUser, $toUser);
        }
      }
    }
    return $this->response->raw('success');
  }
  /**
   * 文本消息回复
   * @param [type] $msg 消息内容
   * @param [type] $fromUser  公众号原始ID
   * @param [type] $toUser  openId
   * @return void
   * @author QianLong <838808603@qq.com>
   * @date 2022-07-18 13:31:42
   * @editAuthor QianLong <838808603@qq.com>
   * @editDescription 
   * @editDate 2022-07-18 13:31:42
   */
  public function wxNoticeText($msg, $fromUser, $toUser)
  {
    if (empty($msg)) {
      return $this->response->raw('success');
    }
    $returnWx['FromUserName'] = $fromUser;
    $returnWx['ToUserName'] = $toUser;
    $returnWx['MsgType'] = 'text';
    $returnWx['Content'] = $msg;
    $xmlData = $this->mpWeixin->generalWxReply($returnWx);
    return $this->response->raw($xmlData);
  }
  public function wxNoticeImage($media_id, $fromUser, $toUser)
  {
    $returnWx['FromUserName'] = $fromUser;
    $returnWx['ToUserName'] = $toUser;
    $returnWx['MsgType'] = 'image';
    $returnWx['Image']['MediaId'] = $media_id;
    $xmlData = $this->mpWeixin->generalWxReply($returnWx);
    $file = BASE_PATH . '/runtime/dev_raw.txt';
    file_put_contents($file, $xmlData);
    return $this->response->raw($xmlData);
  }
  public function wxNoticeVoice($media_id, $fromUser, $toUser)
  {
    $returnWx['FromUserName'] = $fromUser;
    $returnWx['ToUserName'] = $toUser;
    $returnWx['MsgType'] = 'voice';
    $returnWx['Voice']['MediaId'] = $media_id;
    $xmlData = $this->mpWeixin->generalWxReply($returnWx);
    $file = BASE_PATH . '/runtime/dev_raw.txt';
    file_put_contents($file, $xmlData);
    return $this->response->raw($xmlData);
  }
  public function wxNoticeVideo($media_id, $fromUser, $toUser, $title)
  {
    $returnWx['FromUserName'] = $fromUser;
    $returnWx['ToUserName'] = $toUser;
    $returnWx['MsgType'] = 'video';
    $returnWx['Video']['MediaId'] = $media_id;
    $returnWx['Video']['Title'] = $title;
    $returnWx['Video']['Description'] = $title;
    $xmlData = $this->mpWeixin->generalWxReply($returnWx);
    $file = BASE_PATH . '/runtime/dev_raw.txt';
    file_put_contents($file, $xmlData);
    return $this->response->raw($xmlData);
  }
  public function wxNoticeNews($pic, $fromUser, $toUser, $title, $desc, $url)
  {
    $returnWx['FromUserName'] = $fromUser;
    $returnWx['ToUserName'] = $toUser;
    $returnWx['MsgType'] = 'news';
    $returnWx['ArticleCount'] = 1;
    $returnWx['Articles']['item']['PicUrl'] = $pic;
    $returnWx['Articles']['item']['Title'] = $title;
    $returnWx['Articles']['item']['Description'] = $desc;
    $returnWx['Articles']['item']['Url'] = $url;
    $xmlData = $this->mpWeixin->generalWxReply($returnWx);
    $file = BASE_PATH . '/runtime/dev_raw.txt';
    file_put_contents($file, $xmlData);
    return $this->response->raw($xmlData);
  }
  public function oauth()
  {
    $param = $this->request->all();
    $mw_id = (isset($param['mw_id']) && !empty($param['mw_id'])) ? $param['mw_id'] : $param['appid'];
    $infoData = $this->redisCache->getMpWxInfo($mw_id);
    if (!isset($param['code']) || empty($param['code'])) {
      $state = $param['mw_id'] . createId();
      $this->redisCache->getSetMpOauthParam($state, json_encode($param));
      $mpUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $infoData['app_id'] . '&redirect_uri=' . urlencode('http://21ds.cn/mp_weixin/oauth?appid=' . $infoData['app_id']) . '&response_type=code&scope=' . $param['scope'] . '&state=' . $state . '#wechat_redirect';
      return $this->response->redirect($mpUrl);
    }
    $mpUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $infoData['app_id'] . '&secret=' . $infoData['app_secret'] . '&code=' . $param['code'] . '&grant_type=authorization_code';
    $http = new HttpRequest;
    $response = $http->get($mpUrl);
    $responseArr = json_decode($response->body(), true);
    if (isset($responseArr['errcode']) && !empty($responseArr['errcode'])) {
      throw new ApiException(-1, $responseArr['errmsg']);
    }
    $mpUrl = 'https://api.weixin.qq.com/sns/userinfo?access_token=' . $responseArr['access_token'] . '&openid=' . $responseArr['openid'] . '&lang=zh_CN';
    $response = $http->get($mpUrl);
    $responseArr = json_decode($response->body(), true);
    if (isset($responseArr['errcode']) && !empty($responseArr['errcode'])) {
      throw new ApiException(-1, $responseArr['errmsg']);
    }
    $redirectInfo = $this->redisCache->getSetMpOauthParam($param['state']);
    $redirectInfo = json_decode($redirectInfo, true);
    $redirect_uri = urldecode($redirectInfo['redirect_uri']);
    if (strpos($redirect_uri, '?') === false) {
      return $this->response->redirect($redirect_uri . '?' . http_build_query($responseArr));
    }
    return $this->response->redirect($redirect_uri . '&' . http_build_query($responseArr));
  }
}
